﻿using System;
using System.IO;
using System.Configuration;
using System.Text;
using System.Data;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace T.FAS.Runtime.DataModel.Dao
{
    /// <summary>
    /// 本地日志服务
    /// </summary>
    public static class LocalLogService
    {
        private static readonly object s_syncObj = new object();
        private static readonly object s_syncObjSql = new object();
        private static readonly object s_syncObjErr = new object();
        private static readonly object s_syncObjChange = new object();
        private static readonly object s_syncObjStateChange = new object();
        private static readonly object s_syncObjTrace = new object();
        private static readonly string s_logInfoStr = ConfigurationManager.AppSettings["ExecuteLogInfo"];
        private static readonly ExecuteLogSetting s_logInfo;
        //private static readonly string s_isLogNormal = ConfigurationManager.AppSettings["isLogNormal"];
        //private static readonly string s_isLogError = ConfigurationManager.AppSettings["isLogError"];
        //private static readonly string s_isLogSQL = ConfigurationManager.AppSettings["isLogSQL"];
        //private static readonly string s_isLogCDOChange = ConfigurationManager.AppSettings["isLogChange"];
        //private static readonly string s_isLogStateChangeEvent = ConfigurationManager.AppSettings["isLogState"];
        //private static readonly string s_isLogTrace = ConfigurationManager.AppSettings["isLogTrace"];
        //private static readonly string s_logPath = ConfigurationManager.AppSettings["DataAccessLogPath"];

        static LocalLogService()
        {
            if (!string.IsNullOrEmpty(s_logInfoStr))
            {
                try
                {
                    s_logInfo = JsonConvert.DeserializeObject<ExecuteLogSetting>(s_logInfoStr);
                }
                catch
                {
                    s_logInfo = new ExecuteLogSetting
                    {
                        IsLog = false,
                    };
                }
            }
            else
            {
                s_logInfo = new ExecuteLogSetting
                {
                    IsLog = false,
                };
            }
        }

        /// <summary>
        /// 记录异常信息
        /// </summary>
        /// <param name="er">异常信息</param>
        public static void WriteError(System.Exception er, string Msg = null)
        {
            if (!s_logInfo.IsLog || !s_logInfo.IsLogError)
                return;
            lock (s_syncObjErr)
            {
                if (er == null)
                    return;
                string errPath = string.Empty;
                try
                {
                    string path = ErrorLogPath;
                    if (Directory.Exists(path) == false)
                        Directory.CreateDirectory(path);
                    path = Path.Combine(path, string.Format("Error-{0}.txt", DateTime.Now.ToString("yyyyMMddHH")));
                    errPath = path;
                    StringBuilder sb = new StringBuilder(100);
                    sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                    if (!string.IsNullOrEmpty(Msg))
                        sb.AppendLine("UserMsg:" + Msg);
                    sb.AppendLine("Message:" + er.Message);
                    sb.AppendLine("Stack:" + er.StackTrace);
                    if (er.Data != null)
                    {
                        sb.AppendLine("Data:");
                        foreach (var item in er.Data.Keys)
                        {
                            sb.AppendLine("  " + item + " = " + Convert.ToString(er.Data[item]));
                        }
                    }
                    sb.AppendLine("Full Stack:" + er.ToString());
                    if (er.InnerException != null)
                    {
                        sb.AppendLine("InnerException Message:" + er.InnerException.Message);
                        sb.AppendLine("InnerException Stack:" + er.InnerException.StackTrace);

                        if (er.InnerException.Data != null)
                        {
                            sb.AppendLine("InnerException Data:");
                            foreach (var item in er.InnerException.Data.Keys)
                            {
                                sb.AppendLine("  " + item + " = " + Convert.ToString(er.InnerException.Data[item]));
                            }
                        }
                    }

                    File.AppendAllText(path, sb.ToString());
                }
                catch (System.Exception err)
                {
                    if (string.IsNullOrEmpty(errPath) == false)
                    {
                        try
                        {
                            StringBuilder sb = new StringBuilder(100);
                            sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                            sb.AppendLine("Message:" + err.Message);
                            sb.AppendLine("Stack:" + err.StackTrace);
                            File.AppendAllText(errPath, sb.ToString());
                        }
                        catch
                        { }
                    }
                }
            }
        }

        /// <summary>
        /// 记录普通信息
        /// </summary>
        /// <param name="er">异常信息</param>
        public static void Write(object obj)
        {
            if (!s_logInfo.IsLog || !s_logInfo.IsLogNormal)
                return;
            lock (s_syncObj)
            {
                string info = string.Empty;
                if (obj is string)
                    info = obj.ToString();
                else if (obj is DataRow row)
                {
                    StringBuilder sb = new StringBuilder();
                    if (!string.IsNullOrEmpty(row.Table?.TableName))
                        sb.Append($"DataRow所属表：{row.Table.TableName}");
                    sb.Append($"DataRow值:");
                    foreach (var col in row.ItemArray)
                    {
                        sb.Append($"{col},");
                    }
                    info = sb.ToString();
                }
                else
                    info = JsonConvert.SerializeObject(obj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
                if (string.IsNullOrEmpty(info))
                    return;
                string errPath = string.Empty;
                try
                {
                    string path = NormalLogPath;
                    if (Directory.Exists(path) == false)
                        Directory.CreateDirectory(path);
                    path = Path.Combine(path, string.Format("Normal-{0}.txt", DateTime.Now.ToString("yyyyMMddHH")));
                    errPath = path;
                    StringBuilder sb = new StringBuilder(100);
                    sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                    sb.AppendLine(info);

                    File.AppendAllText(path, sb.ToString());
                }
                catch (System.Exception err)
                {
                    if (!string.IsNullOrEmpty(errPath))
                    {
                        try
                        {
                            StringBuilder sb = new StringBuilder(100);
                            sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                            sb.AppendLine("Message:" + err.Message);
                            sb.AppendLine("Stack:" + err.StackTrace);
                            File.AppendAllText(errPath, sb.ToString());
                        }
                        catch
                        { }
                    }
                }
            }
        }

        /// <summary>
        /// 记录SQL
        /// </summary>
        /// <param name="er">异常信息</param>
        public static void WriteSQL(string SQL, IDbDataParameter[] paras = null, SQLLogType type = SQLLogType.DQL)
        {
            if (!s_logInfo.IsLog || !s_logInfo.IsLogSQL)
                return;
            lock (s_syncObjSql)
            {
                if (string.IsNullOrEmpty(SQL))
                    return;
                string errPath = string.Empty;
                try
                {
                    string path = SQLLogPath;
                    if (Directory.Exists(path) == false)
                        Directory.CreateDirectory(path);

                    var prefix = type == SQLLogType.DQL ? "DQL" : "DML";
                    path = Path.Combine(path, string.Format("SQLLog-{0}-{1}.txt", prefix, DateTime.Now.ToString("yyyyMMddHH")));
                    errPath = Path.Combine(path, string.Format("Error-{0}.txt", DateTime.Now.ToString("yyyyMMddHH")));
                    StringBuilder sb = new StringBuilder(100);
                    sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                    sb.AppendLine(SQL);
                    if (paras != null && paras.Length > 0)
                    {
                        foreach (var para in paras)
                        {
                            if (para == null)
                                continue;
                            string parValString = default;
                            if (para.Value is DateTime dateTimeVal)
                            {
                                parValString = dateTimeVal.ToString("yyyy-MM-dd HH:mm:ss.fff");
                            }
                            else
                            {
                                parValString = para.Value?.ToString();
                            }
                            sb.AppendLine($"ParaName:{para.ParameterName}, ParaValue:{parValString}");
                        }
                    }
                    File.AppendAllText(path, sb.ToString());
                }
                catch (System.Exception err)
                {
                    if (string.IsNullOrEmpty(errPath) == false)
                    {
                        try
                        {
                            StringBuilder sb = new StringBuilder(100);
                            sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                            sb.AppendLine("Message:" + err.Message);
                            sb.AppendLine("Stack:" + err.StackTrace);
                            File.AppendAllText(errPath, sb.ToString());
                        }
                        catch
                        { }
                    }
                }
            }
        }

        /// <summary>
        /// 记录普通信息
        /// </summary>
        /// <param name="er">异常信息</param>
        public static void WriteChangeLog(object obj)
        {
            if (!s_logInfo.IsLog || !s_logInfo.IsLogChange)
                return;
            lock (s_syncObjChange)
            {
                string info = string.Empty;
                if (obj == null)
                    return;
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff" };
                info = JsonConvert.SerializeObject(obj, Formatting.None, timeConverter);
                string errPath = string.Empty;
                try
                {
                    string path = ChangeLogPath;
                    if (Directory.Exists(path) == false)
                        Directory.CreateDirectory(path);
                    path = Path.Combine(path, string.Format("ChangeLog-{0}.txt", DateTime.Now.ToString("yyyyMMddHH")));
                    errPath = path;
                    StringBuilder sb = new StringBuilder(100);
                    sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                    sb.AppendLine(info);

                    File.AppendAllText(path, sb.ToString());
                }
                catch (System.Exception err)
                {
                    if (!string.IsNullOrEmpty(errPath))
                    {
                        try
                        {
                            StringBuilder sb = new StringBuilder(100);
                            sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                            sb.AppendLine("Message:" + err.Message);
                            sb.AppendLine("Stack:" + err.StackTrace);
                            File.AppendAllText(errPath, sb.ToString());
                        }
                        catch
                        { }
                    }
                }
            }
        }

        /// <summary>
        /// 记录状态机变更后事件MQ消息
        /// </summary>
        /// <param name="er">异常信息</param>
        public static void WriteStateChangeLog(object obj)
        {
            if (!s_logInfo.IsLog || !s_logInfo.IsLogState)
                return;
            lock (s_syncObjStateChange)
            {
                string info = string.Empty;
                if (obj == null)
                    return;
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff" };
                info = JsonConvert.SerializeObject(obj, Formatting.None, timeConverter);
                string errPath = string.Empty;
                try
                {
                    string path = StateChangeLogPath;
                    if (Directory.Exists(path) == false)
                        Directory.CreateDirectory(path);
                    path = Path.Combine(path, string.Format("StateChangeLog-{0}.txt", DateTime.Now.ToString("yyyyMMddHH")));
                    errPath = path;
                    StringBuilder sb = new StringBuilder(100);
                    sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                    sb.AppendLine(info);

                    File.AppendAllText(path, sb.ToString());
                }
                catch (System.Exception err)
                {
                    if (!string.IsNullOrEmpty(errPath))
                    {
                        try
                        {
                            StringBuilder sb = new StringBuilder(100);
                            sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                            sb.AppendLine("Message:" + err.Message);
                            sb.AppendLine("Stack:" + err.StackTrace);
                            File.AppendAllText(errPath, sb.ToString());
                        }
                        catch
                        { }
                    }
                }
            }
        }

        /// <summary>
        /// 记录普通信息
        /// </summary>
        /// <param name="er">异常信息</param>
        public static void WriteTrace(object obj)
        {
            if (!s_logInfo.IsLog || !s_logInfo.IsLogTrace)
                return;
            lock (s_syncObjTrace)
            {
                string info = string.Empty;
                if (obj == null)
                    return;
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff" };
                info = JsonConvert.SerializeObject(obj, Formatting.None, timeConverter);
                string errPath = string.Empty;
                try
                {
                    string path = TraceLogPath;
                    if (Directory.Exists(path) == false)
                        Directory.CreateDirectory(path);
                    path = Path.Combine(path, string.Format("TraceLog-{0}.txt", DateTime.Now.ToString("yyyyMMddHH")));
                    errPath = path;
                    StringBuilder sb = new StringBuilder(100);
                    sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                    sb.AppendLine(info);

                    File.AppendAllText(path, sb.ToString());
                }
                catch (System.Exception err)
                {
                    if (!string.IsNullOrEmpty(errPath))
                    {
                        try
                        {
                            StringBuilder sb = new StringBuilder(100);
                            sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "=========================================================");
                            sb.AppendLine("Message:" + err.Message);
                            sb.AppendLine("Stack:" + err.StackTrace);
                            File.AppendAllText(errPath, sb.ToString());
                        }
                        catch
                        { }
                    }
                }
            }
        }

        #region Private Funcs
        private static string SQLLogPath
        {
            get
            {
                return Path.Combine(LogPath, "DataAccessSQLLog");
            }
        }

        private static string ErrorLogPath
        {
            get
            {
                return Path.Combine(LogPath, "DataAccessErrorLog");
            }
        }

        private static string NormalLogPath
        {
            get
            {
                return Path.Combine(LogPath, "DataAccessNormalLog");
            }
        }

        private static string ChangeLogPath
        {
            get
            {
                return Path.Combine(LogPath, "DataAccessChangeLog");
            }
        }

        private static string StateChangeLogPath
        {
            get
            {
                return Path.Combine(LogPath, "DataAccessStateChangeLog");
            }
        }

        private static string TraceLogPath
        {
            get
            {
                return Path.Combine(LogPath, "DataAccessTraceLog");
            }
        }

        private static string LogPath
        {
            get
            {
                if (string.IsNullOrEmpty(s_logInfo.DataAccessLogPath))
                {
                    return Path.Combine(Environment.CurrentDirectory, "log");
                }
                else
                    return s_logInfo.DataAccessLogPath;
            }
        }

        #endregion
    }

    public enum SQLLogType
    {
        DQL = 0,
        DML = 1,
    }

    public enum DacLogType
    {
        Local = 0,
        LogService = 1,
    }

    public class ExecuteLogSetting
    {
        public bool IsLog { get; set; }
        public bool IsLogNormal { get; set; }
        public bool IsLogError { get; set; }
        public bool IsLogSQL { get; set; }
        public bool IsLogChange { get; set; }
        public bool IsLogState { get; set; }
        public bool IsLogTrace { get; set; }
        public string DataAccessLogPath { get; set; }
        public DacLogType LogType { get; set; }
    }
}
